package com.linciping.gradle.inject.view

import com.linciping.gradle.inject.view.utils.ClickMethodUtils
import com.linciping.gradle.inject.view.utils.FragmentHook
import com.linciping.gradle.inject.view.utils.HookUtil
import org.objectweb.asm.*
import org.objectweb.asm.commons.AdviceAdapter

class InjectMethodVisitor(
    classReader: ClassReader,
    private val visitedFragmentMethods: HashSet<String>,
    private val isClickMethod: Boolean,
    methodVisitor: MethodVisitor?,
    access: Int,
    name: String?,
    private val descriptor: String?
) : AdviceAdapter(
    ASM7, methodVisitor,
    access, name, descriptor,
) {
    private var isHasTracked = false
    private var isHasInstrumented = false
    private val classNam = classReader.className
    private val nameDesc = name + descriptor
    private val superClassName = classReader.superName

    override fun onMethodEnter() {
        if (isClickMethod) {
            val viewVarParam = ClickMethodUtils.getViewParamIndex(descriptor!!,access)
            println("class= $classNam;method=$name;onMethodEnter")
            visitVarInsn(ALOAD, viewVarParam)
            visitMethodInsn(
                INVOKESTATIC,
                "com/linciping/gradle/inject/ViewClickCount",
                "onViewClick",
                "(Landroid/view/View;)V",
                false
            )
        }
    }

    //region fragment插桩
    override fun visitAnnotation(descriptor: String?, visible: Boolean): AnnotationVisitor {
        //判断是否存在已处理注解，如果有则不需要再处理
        if (descriptor.equals(FragmentHook.FRAGMENT_HOOK_TAG)) {
            isHasInstrumented = true
        }
        return super.visitAnnotation(descriptor, visible)
    }

    override fun onMethodExit(opcode: Int) {
        super.onMethodExit(opcode)
        //如果已处理，则不用再操作
        if (isHasInstrumented) return
        //判断是否是fragment，并且是我们需要处理的方法
        if (HookUtil.isFragment(superClassName) && FragmentHook.FRAGMENT_METHODS.containsKey(nameDesc)) {
            val fragmentHookMethodCell = FragmentHook.FRAGMENT_METHODS[nameDesc]!!
            //调用fragment回调桩
            HookUtil.visitMethodWithLoadedParams(
                this,
                Opcodes.INVOKESTATIC,
                FragmentHook.FRAGMENT_HOOK_CLASS,
                fragmentHookMethodCell.agentName,
                fragmentHookMethodCell.agentDesc,
                fragmentHookMethodCell.paramsStart,
                fragmentHookMethodCell.paramsCount,
                fragmentHookMethodCell.opcodes
            )
            //代表已经处理这个方法了
            visitedFragmentMethods.add(nameDesc)
            isHasTracked = true
        }
    }

    override fun visitEnd() {
        super.visitEnd()
        //如果已经处理，加上注解标记
        if (isHasTracked) {
            visitAnnotation(FragmentHook.FRAGMENT_HOOK_TAG, false)
        }
    }
    //endregion
}